package com.kenliang.toolslib.rsa;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author KenLiang
 * @description:
 * @date Created in 11:33 AM 2020/5/19.
 */
public class RSAUtils {
    private static final String DEFAULT_PRIVATE_KEY_STRING = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAi7fBMQLUH+dAGBcb7cQRLayk9g36GP+zrW6V55MnlGFqNW09xYPDUZeVmaacVsldWkJzy4KZsXpDzqFVQvvQFwIDAQABAkAkum1iwOeaa2QB8TE6U6xgYV4MAKiaIb3N/aASfDCPZJeQijldDZi2hMpvS7bKomCx5I1QbbTeiJ+oakgDmRwBAiEA3qNra7627ZgTUYD3/yelVO+1yxCtvzBAe7HmiCCrJ5cCIQCgp3AMwx2VxH2JCxkn0YIiJh4dsID3kQOZ2psOEm2rgQIhAM32OGYQpIHgcd6whLwTHSwaJf+ZimKYbM8BoNbGAhA5AiBAUOgV4+MrOz+6ppvKiiCcBUCXSDtJYV/cr1zV9GC9gQIhAI9j1Nin1g8+ohYYHaqBX/oufKiYUuHAsRVMOcjMjO4L";
    public static final String DEFAULT_PUBLIC_KEY_STRING = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIu3wTEC1B/nQBgXG+3EES2spPYN+hj/s61uleeTJ5RhajVtPcWDw1GXlZmmnFbJXVpCc8uCmbF6Q86hVUL70BcCAwEAAQ==";

    public RSAUtils() {
    }

    public static void main(String[] args) throws Exception {
        if (null == args || args.length == 0) {
            System.out.println("解析参数异常");
            System.exit(0);
        }

        String command = args[0];
        if (command.equals("-h")) {
            System.out.println("java -cp cwop-commons-1.0.0.jar com.cloudwise.cwop.security.RSAUtils [-h|gen|encrypt|decrypt]");
            System.exit(0);
        } else if (command.equals("gen")) {
            String[] keys = genKeyPair(512);
            System.out.println("私钥:" + keys[0]);
            System.out.println("公钥:" + keys[1]);
        } else {
            String result;
            if (command.equals("encrypt")) {
                if (args.length == 1) {
                    System.out.println("请传入加密字符串");
                    System.exit(0);
                }

                if (args.length == 2) {
                    result = encrypt(args[1]);
                    System.out.println("公钥:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIu3wTEC1B/nQBgXG+3EES2spPYN+hj/s61uleeTJ5RhajVtPcWDw1GXlZmmnFbJXVpCc8uCmbF6Q86hVUL70BcCAwEAAQ==");
                    System.out.println("加密结果:" + result);
                } else {
                    result = encrypt(args[1], args[2]);
                    System.out.println("公钥:" + args[1]);
                    System.out.println("加密结果:" + result);
                }
            } else if (command.equals("decrypt")) {
                if (args.length == 1) {
                    System.out.println("请传入加密字符串");
                    System.exit(0);
                }

                if (args.length == 2) {
                    result = decrypt(args[1]);
                    System.out.println("私钥:MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAi7fBMQLUH+dAGBcb7cQRLayk9g36GP+zrW6V55MnlGFqNW09xYPDUZeVmaacVsldWkJzy4KZsXpDzqFVQvvQFwIDAQABAkAkum1iwOeaa2QB8TE6U6xgYV4MAKiaIb3N/aASfDCPZJeQijldDZi2hMpvS7bKomCx5I1QbbTeiJ+oakgDmRwBAiEA3qNra7627ZgTUYD3/yelVO+1yxCtvzBAe7HmiCCrJ5cCIQCgp3AMwx2VxH2JCxkn0YIiJh4dsID3kQOZ2psOEm2rgQIhAM32OGYQpIHgcd6whLwTHSwaJf+ZimKYbM8BoNbGAhA5AiBAUOgV4+MrOz+6ppvKiiCcBUCXSDtJYV/cr1zV9GC9gQIhAI9j1Nin1g8+ohYYHaqBX/oufKiYUuHAsRVMOcjMjO4L");
                    System.out.println("解密结果:" + result);
                } else {
                    result = decrypt(args[1], args[2]);
                    System.out.println("私钥:" + args[1]);
                    System.out.println("解密结果:" + result);
                }
            } else {
                System.out.println("参数调用异常");
                System.out.println("例: java -cp cwop-commons-1.0.0.jar com.cloudwise.cwop.security.RSAUtils [-h|gen|encrypt|decrypt]");
                System.exit(0);
            }
        }

    }

    public static String decrypt(String cipherText) throws Exception {
        return decrypt((String) null, cipherText);
    }

    public static String decrypt(String privateKeyText, String cipherText) throws Exception {
        PrivateKey privateKey = getPrivateKey(privateKeyText);
        return decrypt(privateKey, cipherText);
    }

    public static PublicKey getPublicKeyByX509(String x509File) throws IOException {
        if (x509File != null && x509File.length() != 0) {
            FileInputStream in = null;

            PublicKey var4;
            try {
                in = new FileInputStream(x509File);
                CertificateFactory factory = CertificateFactory.getInstance("X.509");
                Certificate cer = factory.generateCertificate(in);
                var4 = cer.getPublicKey();
            } catch (Exception var8) {
                throw new IllegalArgumentException("Failed to get public key", var8);
            } finally {
                close(in);
            }

            return var4;
        } else {
            return getPublicKey((String) null);
        }
    }

    public static PrivateKey getPrivateKey(String privateKeyText) throws Exception {
        if (privateKeyText == null || privateKeyText.length() == 0) {
            privateKeyText = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAi7fBMQLUH+dAGBcb7cQRLayk9g36GP+zrW6V55MnlGFqNW09xYPDUZeVmaacVsldWkJzy4KZsXpDzqFVQvvQFwIDAQABAkAkum1iwOeaa2QB8TE6U6xgYV4MAKiaIb3N/aASfDCPZJeQijldDZi2hMpvS7bKomCx5I1QbbTeiJ+oakgDmRwBAiEA3qNra7627ZgTUYD3/yelVO+1yxCtvzBAe7HmiCCrJ5cCIQCgp3AMwx2VxH2JCxkn0YIiJh4dsID3kQOZ2psOEm2rgQIhAM32OGYQpIHgcd6whLwTHSwaJf+ZimKYbM8BoNbGAhA5AiBAUOgV4+MrOz+6ppvKiiCcBUCXSDtJYV/cr1zV9GC9gQIhAI9j1Nin1g8+ohYYHaqBX/oufKiYUuHAsRVMOcjMjO4L";
        }

        byte[] privateKeyBytes = Base64.base64ToByteArray(privateKeyText);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
        return factory.generatePrivate(spec);
    }

//    public static PublicKey getPublicKey(String publicKeyText) {
//        if (publicKeyText == null || publicKeyText.length() == 0) {
//            publicKeyText = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIu3wTEC1B/nQBgXG+3EES2spPYN+hj/s61uleeTJ5RhajVtPcWDw1GXlZmmnFbJXVpCc8uCmbF6Q86hVUL70BcCAwEAAQ==";
//        }
//
//        try {
//            byte[] publicKeyBytes = Base64.base64ToByteArray(publicKeyText);
//            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
//            KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign");
//            return keyFactory.generatePublic(x509KeySpec);
//        } catch (Exception var4) {
//            throw new IllegalArgumentException("Failed to get public key", var4);
//        }
//    }

    public static PublicKey getPublicKey(String publicKeyText) {
        try {
            byte[] keyBytes;
            keyBytes = Base64.base64ToByteArray(publicKeyText);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        } catch (Exception var4) {
            throw new IllegalArgumentException("Failed to get public key", var4);
        }

//        if (publicKeyText == null || publicKeyText.length() == 0) {
//            publicKeyText = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIu3wTEC1B/nQBgXG+3EES2spPYN+hj/s61uleeTJ5RhajVtPcWDw1GXlZmmnFbJXVpCc8uCmbF6Q86hVUL70BcCAwEAAQ==";
//        }
//
//        try {
//            byte[] publicKeyBytes = Base64.base64ToByteArray(publicKeyText);
//            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
//            KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign");
//            return keyFactory.generatePublic(x509KeySpec);
//        } catch (Exception var4) {
//            throw new IllegalArgumentException("Failed to get public key", var4);
//        }
    }

//    public static PublicKey getPublicKeyByBytes(byte[] publicKeyBytes) {
//        try {
//            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
//            KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign");
//            return keyFactory.generatePublic(x509KeySpec);
//        } catch (Exception var3) {
//            throw new IllegalArgumentException("Failed to get public key", var3);
//        }
//    }
    public static PublicKey getPublicKeyByBytes(byte[] publicKeyBytes) {
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        } catch (Exception var3) {
            throw new IllegalArgumentException("Failed to get public key", var3);
        }
    }

    public static PublicKey getPublicKeyByPublicKeyFile(String publicKeyFile) throws IOException {
        if (publicKeyFile != null && publicKeyFile.length() != 0) {
            FileInputStream in = null;

            try {
                in = new FileInputStream(publicKeyFile);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int len = 0;
                byte[] b = new byte[64];

                while ((len = in.read(b)) != -1) {
                    out.write(b, 0, len);
                }

                byte[] publicKeyBytes = out.toByteArray();
                X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyBytes);
                KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
                PublicKey var8 = factory.generatePublic(spec);
                return var8;
            } catch (Exception var12) {
                throw new IllegalArgumentException("Failed to get public key", var12);
            } finally {
                close(in);
            }
        } else {
            return getPublicKey((String) null);
        }
    }

    public static void close(Closeable x) throws IOException {
        if (x != null) {
            x.close();
        }
    }

    public static String decrypt(PrivateKey privateKey, String cipherText) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(2, privateKey);
        if (cipherText != null && cipherText.length() != 0) {
            byte[] cipherBytes = Base64.base64ToByteArray(cipherText);
            byte[] plainBytes = cipher.doFinal(cipherBytes);
            return new String(plainBytes);
        } else {
            return cipherText;
        }
    }

    public static String encrypt(String plainText) throws Exception {
        return encrypt((String) null, plainText);
    }

    public static String encrypt(String key, String plainText) throws Exception {
        if (key == null) {
            key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIu3wTEC1B/nQBgXG+3EES2spPYN+hj/s61uleeTJ5RhajVtPcWDw1GXlZmmnFbJXVpCc8uCmbF6Q86hVUL70BcCAwEAAQ==";
        }

        byte[] keyBytes = Base64.base64ToByteArray(key);
        return encrypt(keyBytes, plainText);
    }

    public static String encrypt(byte[] keyBytes, String plainText) throws Exception {
        PublicKey publicKey = getPublicKeyByBytes(keyBytes);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(1, publicKey);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        return Base64.byteArrayToBase64(encryptedBytes);
    }

    public static byte[][] genKeyPairBytes(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
        byte[][] keyPairBytes = new byte[2][];
        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "SunRsaSign");
        gen.initialize(keySize, new SecureRandom());
        KeyPair pair = gen.generateKeyPair();
        keyPairBytes[0] = pair.getPrivate().getEncoded();
        keyPairBytes[1] = pair.getPublic().getEncoded();
        return keyPairBytes;
    }

    public static String[] genKeyPair(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
        byte[][] keyPairBytes = genKeyPairBytes(keySize);
        String[] keyPairs = new String[]{Base64.byteArrayToBase64(keyPairBytes[0]), Base64.byteArrayToBase64(keyPairBytes[1])};
        return keyPairs;
    }
}
